#! /usr/bin/python
# -*- coding: utf-8 -*-
'''Parse greek service texts. Turn to unicode.'''

import pygtk
pygtk.require('2.0')
import gtk
import codecs
import re
import os
import sys
import unicodedata

# formerly - ucs8conv, renamed
#import hipconv
import booklst
import hip_config
from hipview import Text
import hipcomment

#conv = hipconv.Repl()
brac = hipcomment.Brackets()

def count_files(books):

    file_count = 0

    for book in books:
        book = ''.join(["/usr/local/lib/greek_lib/", book])

#        book = os.path.join(os.getcwd(), "greek_lib", book)

        for file in os.listdir(book):
            if file.endswith('xml'):
                file_count += 1

#        print file_count

    return file_count

def f_search(books=None, s_word=None):
    '''main search function'''

    cur_file = 0

    res = []
    global count
    count = 0

#    import pdb; pdb.set_trace()

    word = s_word.decode('utf-8')
    word = unicodedata.normalize('NFD', word)

#    regex = re.compile(word, re.U)

    for j in books:
        j = os.path.join(os.getcwd(), "greek_lib", j)
        f_names = os.listdir(j)
#        print j

        for i in f_names:
            if i.endswith('.xml'):
                file_path = os.path.join(j, i)
#                print "file_path: ", file_path
                fp = codecs.open(file_path, "rb", "utf8")
                f_lines = fp.readlines()
                fp.close()

                for str_num in range(len(f_lines)):
#                    line = f_lines[str_num].encode('utf8')
                    line = f_lines[str_num]

#                    if regex.search(line):
                    if word in line:
                        count += 1
#                        res.append((file_path, str_num, f_lines[str_num]))
                        res.append([file_path, str_num, f_lines[str_num]])
#                        print 'found', file_path
#                        print line
#    print res

    # sort found results buy month (cut trailing piece like 'aug.xml' from file path)
    # and sort by it
#    def qudos(inpStr):
#        return inpStr[0][-7:]
#    res = sorted(res, key=qudos)

    return res


#def f_search(books=None, s_word=None):
#    '''main search function'''
#
#    # number of 'hip' files in given group of books
#    num_files = count_files(books)
#    cur_file = 0
#
#    res = []
#    global count
#    count = 0
##    word = s_word.decode('utf-8')
#    word = s_word
##        word = word.lower()
#
#    print word
#            
##    if word.startswith('\"'):
##        word = word.replace('\"', '')
##        patt = "\s" + word + "\s"
##        patt = patt.decode('utf8')
##
###            print 'patt', patt
##        regex = re.compile(patt, re.U)
##            
##    elif word.endswith('*'):
###        print 'w*'
##        word = word.replace('*', '')
###        patt = word + ".*\s"
##        patt = "\s" + word + ".*?\s"
###        print patt
##        regex = re.compile(patt, re.U)
##
##    elif word.startswith('*'):
##        word = word.replace('*', '')
##        patt = "\s\w+?" + word + "\s"
###        word = '\s\w+?гул[\s\n\.,;:!\?@"\']'
###        word = '\s\w+?[\s\n\.,;:!\?@"\']'
###        print patt
##        regex = re.compile(patt, re.U)
#
#    patt = word
#    if face.case_ins:
#        regex = re.compile(patt, re.U | re.I)
#    else:
#        regex = re.compile(patt, re.U)
#
#    for j in books:
##        j = ''.join(["/usr/local/lib/hip-tools/hiplib/", j])
#        j = os.path.join(os.getcwd(), "greek_lib", j)
##        print j 
#        f_names = os.listdir(j)
#
#        for i in f_names:
#            if i.endswith('.xml'):
#                cur_file += 1
##                    perc = round(float(cur_file)/float(num_files), 1)
#
#                # calculate percent of work done so far
#                perc = float(cur_file)/float(num_files)
#                face.pr_bar.set_fraction(perc)
#                # these are nesessary to steal control from gtk main loop
#                # else progrees bar wont move untill job's done
#                while gtk.events_pending():
#                    gtk.main_iteration()
#
#                file_path = os.path.join(j, i)
##                    print "file_path: ", file_path
#                fp = codecs.open(file_path, "rb", "utf8")
#                f_lines = fp.readlines()
#                fp.close()
#
#                for str_num in range(len(f_lines)):
#                    line = f_lines[str_num]
#
#                    # clean all apostrophs (stresses) from searched text
##                    if not face.stress_toggle:
##                        line = line.replace('\'', '')
##                        line = line.replace('`', '')
##                        line = line.replace('^', '')
##                    if '%<' or '%>' in line:
##                            print line
##                        line = line.replace('%<','')
##                        line = line.replace('%>', '')
#                    if regex.search(line):
#                        count += 1
#                        res.append((file_path, str_num, f_lines[str_num]))
#
#    return res

def destroy_cb(widget):
    gtk.main_quit()
    return False

def entry_cb(ent):
    """Callback for entry widg
       Look for word in results of primary search

    """
    
    global search_res
    global res_num
    res_num = 0
#    search_res = []

    col_num = 2
    search = ent.get_text()

    data = [search]
    def find_match(model, path, iter, data):

        match_line = model.get_value(iter, col_num)
        if match_line.find(data[0]) >= 0:
            data.append(path)
    face.new_win.modelfilter.foreach(find_match, data)
    search_res = data[1:]
    if search_res:
        face.new_win.selection.select_path(search_res[0])
        face.new_win.tv.scroll_to_cell(search_res[0])
    else:
        print 'no match found'

def on_key_press_event(widget, event):
    """Callback for Viewer"""

    keyname = gtk.gdk.keyval_name(event.keyval)

    global res_num
    selection = face.new_win.selection
    model, path = selection.get_selected_rows()
    # get iter in Viewer (found entries)
    iter_v = model.get_iter(path[0])
    file_path = model.get_value(iter_v, 0) 
    found_raw = model.get_value(iter_v, 1)    

    # if event is from tree-view, open selected file
    if isinstance(widget, gtk.TreeView):

        if keyname == "Return":
            fp = codecs.open(file_path, "rb", "utf8")
            f_lines = fp.readlines()
            fp.close()

            txt_ins = ''.join(f_lines)

            # create window to output selected text
            txt_win = SeText()

            txt_win.window3.set_title(face.path2name(file_path))

            txt_win.ins_txt(txt_ins, found_raw)


    # if event is from entry, search tree
    elif isinstance(widget, gtk.Entry):

        # next result is search (Viewer)
        if event.state & gtk.gdk.CONTROL_MASK:
            if keyname == "n" or keyname == "Cyrillic_te":
                
                if res_num < len(search_res) - 1:
                    res_num += 1
                    face.new_win.selection.select_path(search_res[res_num])
                    face.new_win.tv.scroll_to_cell(search_res[res_num])
                    face.new_win.tv.set_cursor_on_cell(search_res[res_num])

            # prevuous result is search (Viewer)
            if keyname == "p" or keyname == "Cyrillic_ze":
                if res_num != 0:
                    res_num -= 1
                    face.new_win.selection.select_path(search_res[res_num])
                    face.new_win.tv.scroll_to_cell(search_res[res_num])
                    face.new_win.tv.set_cursor_on_cell(search_res[res_num])

##################CLASSES#################################


class Popup:
    def __init__(self, text=None):
#        self.title = ""
        self.text = text
        dialog = gtk.Dialog(title='warning')
        label = gtk.Label(self.text)
        dialog.vbox.pack_start(label, True, True, 10)
        label.show()
        dialog.show()

class SeText(Text):
    def __init__(self):
        Text.__init__(self, face.config)
#        self.config = face.config
#        self.sl_font = face.config.default_font

    def ins_txt(self, new_txt=None, found_raw=None):

        if found_raw:
            self.found_raw = found_raw

        self.tag_table = self.textbuffer.get_tag_table()
        self.my_text = gtk.TextTag()
        self.tag_table.add(self.my_text)

        if new_txt:
            self.base_txt = new_txt
        if not self.plain: 
#            conv_txt = brac.repl_brac(self.base_txt, True)[0]
#            conv_txt = conv(conv_txt, self.uni)

#            conv_txt = conv(self.base_txt, self.uni)
#            self.textbuffer.set_text(conv_txt)
            self.textbuffer.set_text(self.base_txt)
            if self.sl_font == self.plain_font:
                self.sl_font = self.sl_font_prev

        else:
            self.textbuffer.set_text(self.base_txt)
            self.sl_font_prev = self.sl_font
            self.sl_font = self.plain_font

        self.iter = self.textbuffer.get_iter_at_line_offset(self.found_raw, 0)
        self.iter2 = self.textbuffer.get_iter_at_line_offset(self.found_raw + 1, 0)
        one = self.textbuffer.create_mark(None, self.iter)
        self.textbuffer.place_cursor(self.iter)
        self.textview.scroll_to_mark(one, 0.0, True, 0.0, 1.0)
        self.found_text = gtk.TextTag()
        self.found_text.set_property("background", "green")
        self.tag_table.add(self.found_text)
        self.textbuffer.apply_tag(self.found_text, self.iter, self.iter2)

        self.style_txt()  
        self.f_select.set_font_name(self.sl_font)

        # Here's patch by S. Maryasin, makes %<L%>etters red
        if not self.plain:
            # преобразуем "костыльные" метки \1 и \2 в киноварь
            red = gtk.TextTag()
            self.tag_table.add(red)
            red.set_property("foreground", "red")
            i = self.textbuffer.get_start_iter()
            while i.get_char() != '\0':
                if i.get_char() == '\1': # начало выделения, %<
                    i.forward_char()
                    self.textbuffer.backspace(i, False, True) # удаляем метку
                    start = i.get_offset() # запоминаем позицию
                if i.get_char() == '\2': # конец выделения, %>
                    i.forward_char()
                    self.textbuffer.backspace(i, False, True)
                    self.textbuffer.apply_tag(red, self.textbuffer.get_iter_at_offset(start), i)
                i.forward_char() # next i
            # end of patch. See also changes in ucs8conv

class Viewer:
    ''' List of found entries

    '''

    def __init__(self):
        self.res_num = 0
        self.text = 'Searching...'
        window2 = gtk.Window(gtk.WINDOW_TOPLEVEL)
        window2.set_resizable(True)
        window2.set_border_width(10)
        window2.set_size_request(850, 400)

        window2.set_title("Просмотр результатов")
        window2.set_border_width(0)
#        window2.connect('key_press_event', on_key_press_event)

        box1 = gtk.VBox(False, 0)
        window2.add(box1)
        box1.show()
        box2 = gtk.VBox(False, 10)
        box2.set_border_width(10)
        box1.pack_start(box2, True, True, 0)
        box2.show()

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.model = gtk.ListStore(str, int, str, str)
        self.tv = gtk.TreeView(self.model)
        self.selection = self.tv.get_selection()

        self.tv.connect('key_press_event', on_key_press_event)

        self.modelfilter = self.model.filter_new()
#        self.modelfilter.set_visible_func(vis, self.small)
        self.tv.set_model(self.modelfilter)

        sw.add(self.tv)

        self.label = gtk.Label() 
        self.entry = gtk.Entry()
        
        cell1 = gtk.CellRendererText()
        cell2 = gtk.CellRendererText()
        self.column = gtk.TreeViewColumn("File_path", cell1, text=3)
        self.column2 = gtk.TreeViewColumn("String", cell2, text=2)
        self.tv.append_column(self.column)
        self.tv.append_column(self.column2)
        self.tv.set_search_column(2)
        
        sw.show_all()
        self.tv.show()
        box2.pack_start(self.label, False, False, 0)
        box2.pack_start(sw)
        box2.pack_start(self.entry, False, False, 0)

        self.entry.connect('activate', entry_cb)
        self.entry.connect('key_press_event', on_key_press_event)
        self.label.set_text("Найдено " + str(count) + " совпадений")
        self.entry.show()
        self.label.show()

        window2.show()
    def ins(self, res):
        
        for i in res:
            iter = self.model.append()
            self.model.set(iter, 0, i[0])
            self.model.set(iter, 1, i[1])
            self.model.set(iter, 2, i[2])
            path_s_u = face.path2name(i[0]).decode('utf8')[:40]
            self.model.set(iter, 3, path_s_u)
#            self.model.set(iter, 3, '')
#            self.model.set(iter, 3, path2name(i[0]))
 
class Manager:
    '''Main programm window'''

    def __init__(self):

#        self.case_ins = False
        # create configurations object
        self.config = hip_config.Service(".grsearch.config")
#        print self.config.default_search_group

        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_title("greek-search")
        self.window.connect("destroy", destroy_cb) 
#        self.window.connect("key_press_event", self.manager_keys) 


        self.window.set_border_width(10)
        self.window.set_size_request(500, 200)

        self.vbox = gtk.VBox(False, 0)
        self.hbox = gtk.HBox(False, 0)
        self.entry = gtk.Entry()
        self.combo = gtk.combo_box_new_text()
        self.toggle1 = gtk.CheckButton("Вкл. ударения")
        self.toggle2 = gtk.CheckButton("Учит. регистр")
        self.button = gtk.Button('Search')
        self.pr_bar = gtk.ProgressBar()

        self.vbox.pack_start(self.entry, False, False, 0)
        self.vbox.pack_start(self.combo, False, False, 0)
#        self.vbox.pack_start(self.button, True, False, 10)
        self.hbox.pack_start(self.toggle1, False, False, 10)
        self.hbox.pack_start(self.toggle2, False, False, 10)
        self.hbox.pack_end(self.button, False, False, 10)
        self.vbox.pack_start(self.hbox, True, False, 0)
        self.vbox.pack_start(self.pr_bar, False, False, 0)
        self.window.add(self.vbox)
        
        self.entry.connect("key_press_event", self.manager_keys) 
        
        self.combo_lst = ['All_services','Minologion_base', 'Minologion extra', 'Minologion all', 'Octoechos', 'Orologion', 'Penticostartion', 'Triodion',]

        for i in self.combo_lst: 
            self.combo.append_text(i.strip())

        self.entry.show()
        self.combo.show()
        self.toggle1.show()
        self.toggle2.show()
        self.button.show()
        self.vbox.show()
        self.hbox.show()
        self.pr_bar.show()
        self.window.show()

        self.dicti = {'All_services': ['Minologion/min_base', 'Minologion/min_ext', 'Octoechos', 'Orologion', 'Penticostarion', 'Triodion'],'Minologion_base': ['Minologion/min_base'], 'Minologion extra': ['Minologion/min_ext'], 'Minologion all': ['Minologion/min_base', 'Minologion/min_ext'], 'Octoechos': ['Octoechos'], 'Orologion': ['Orologion'], 'Penticostarion': ['Penticostarion'], 'Triodion': ['Triodion'],}
        
        # passes two objects: itself and the widget:
        self.combo.connect("changed", self.choose)       
        for x in range(len(self.combo_lst)):
            if self.config.default_search_group == self.combo_lst[x]:
                self.combo.set_active(x)

#        self.combo.set_active(0)

        # define checkboxes callbacks
        self.toggle1.connect("toggled", self.stress)
        self.toggle2.connect("toggled", self.case_switch)       

        self.case_ins = True

        # check config for paramater
        if self.config.diacritics_off == 'True':
            self.stress_toggle = False
        elif self.config.diacritics_off == 'False':
            self.stress_toggle = True
        

#        self.button.connect('clicked', new_win_cb)
        self.comm_lst = []
        self.pointer = 0

        self.button.connect('clicked', self.search_it)

        self.gl_book_lst = booklst.listbooks('greek_lib') # , False) # - чтобы не перечислять "лишние" (не описанные) файлы

    def manager_keys(self, widget, event):
        '''Bindings for main window'''

#        if event.state & gtk.gdk.CONTROL_MASK:
        keyname = gtk.gdk.keyval_name(event.keyval)

        if keyname == "Return":
#            print 'Return'
            self.search_it()

        if keyname == "Up":
            print 'Up'
#            if self.comm_lst:

            self.pointer += 1
            print 'pointer', self.pointer
            if self.pointer <= len(self.comm_lst):
                self.entry.set_text(self.comm_lst[len(self.comm_lst) - self.pointer])
            else:
                self.pointer == 1
                self.entry.set_text(self.comm_lst[len(self.comm_lst) - self.pointer])
 
        if keyname == "Down":
            print 'Down'

    def choose(self, widget):
        '''Chooses the books group'''

        get_name = widget.get_active_text() 

        for name in self.dicti:
            if get_name == name:
                self.books = self.dicti[name]
#                print self.books

    def case_switch(self, widget, data=None):

       if widget.get_active():
           self.case_ins = False
       else:
           self.case_ins = True 
        
    def stress(self, widget, data=None):

       if widget.get_active():
           self.stress_toggle = True 
       else:
           self.stress_toggle = False
         
    def search_it(self, button=None):
        '''Main search interface'''

        self.s_word = self.entry.get_text()
        self.comm_lst.append(self.s_word)
#        print self.comm_lst

        # res - list of tuples, containing path, line_num, text
        res = f_search(self.books, self.s_word)
#        print 'self.books', self.books, self.s_word
        if res:
            self.new_win = Viewer()
            self.new_win.ins(res)
            self.new_win.selection.select_path((0,))
        else:
            print 'Didn\'t find anything, sorry.'
            Popup("Ничего не найдено")

    def path2name(self, f_path):
        ''' Convert given path to description string '''

        self.path_ls = []

        while(f_path):
            f_path, tail = os.path.split(f_path)
            if tail == 'greek_lib':
                break
            self.path_ls.insert(0, tail)
                    
        self.desc_str = []
        self.walker(self.gl_book_lst)
        res_str = ' / '.join(self.desc_str)

        return res_str

    def walker(self, book_lst):
        '''recursive funstion for parsing through book list'''

        for book in book_lst:
            if self.path_ls:
                if self.path_ls[0] in book[0]:
                    out = self.path_ls.pop(0)
                    self.desc_str.append(book[1])
                    if book[2]:
                        self.walker(book[2])
            else:
                break

def main():
    gtk.main()
    return 0

if __name__ == '__main__':

    face = Manager()
#    print os.path.realpath(__file__)
#    print config.default_font
    main()

#TODO: sort found entries by month, day. Show title in a title bar of a window
